home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / cpp_libs / perlcl16.lha / perlclass1.6 / perlclass.h < prev    next >
C/C++ Source or Header  |  1992-11-09  |  16KB  |  671 lines

  1. /*
  2.  * Version 1.6
  3.  * Written by Jim Morris,  jegm@sgi.com
  4.  * Kudos to Larry Wall for inventing Perl
  5.  * Copyrights only exist on the regex stuff, and all have been left intact.
  6.  * The only thing I ask is that you let me know of any nifty fixes or
  7.  * additions.
  8.  * 
  9.  * Credits:
  10.  * I'd like to thank Michael Golan <mg@Princeton.EDU> for his critiques
  11.  * and clever suggestions. Some of which have actually been implemented
  12.  */
  13.  
  14. #ifndef    _PERL_H
  15. #define    _PERL_H
  16.  
  17. #include <string.h>
  18. #include "regexp.h"
  19.  
  20. #if    DEBUG
  21. #include    <stdio.h>
  22. #endif
  23.  
  24. #define    INLINE    inline
  25.  
  26. // This is the base class for PerlList, it handles the underlying
  27. // dynamic array mechanism
  28.  
  29. template<class T>
  30. class PerlListBase
  31. {
  32. private:
  33.     enum{ALLOCINC=20};
  34.     T *a;
  35.     int cnt;
  36.     int first;
  37.     int allocated;
  38.     int allocinc;
  39.     void grow(int amnt= 0, int newcnt= -1);
  40.  
  41. protected:
  42.     void compact(const int i);
  43.  
  44. public:
  45. #ifdef    USLCOMPILER
  46.     // USL 3.0 bug with enums losing the value
  47.     PerlListBase(int n= 20)
  48. #else
  49.     PerlListBase(int n= ALLOCINC)
  50. #endif
  51.     {
  52.     a= new T[n];
  53.     cnt= 0;
  54.         first= n>>1;
  55.     allocated= n;
  56.     allocinc= n;
  57. #    ifdef    DEBUG
  58.     fprintf(stderr, "PerlListBase(int %d) a= %p\n", allocinc, a);
  59. #    endif
  60.     }
  61.  
  62.     PerlListBase(const PerlListBase<T>& n);
  63.     PerlListBase<T>& PerlListBase<T>::operator=(const PerlListBase<T>& n);
  64.     virtual ~PerlListBase(){
  65. #       ifdef    DEBUG
  66.     fprintf(stderr, "~PerlListBase() a= %p, allocinc= %d\n", a, allocinc);
  67. #       endif
  68.     delete [] a;
  69.     }
  70.  
  71.     INLINE T& operator[](const int i);
  72.     INLINE const T& operator[](const int i) const;
  73.  
  74.     int count(void) const{ return cnt; }
  75.  
  76.     void add(const T& n);
  77.     void add(const int i, const T& n);
  78.     void erase(void){ cnt= 0; first= (allocated>>1);}
  79. };
  80.  
  81. // PerlList
  82. class PerlStringList;
  83.  
  84. template <class T>
  85. class PerlList: private PerlListBase<T>
  86. {
  87. public:
  88.  
  89.     PerlList(int sz= 10): PerlListBase<T>(sz){}
  90.  
  91.     // stuff I want public to see from PerlListBase
  92.     T& operator[](const int i){return PerlListBase<T>::operator[](i);}
  93.     const T& operator[](const int i) const{return PerlListBase<T>::operator[](i);}
  94.     PerlListBase<T>::count;
  95.  
  96.     // add perl-like synonym
  97.     void reset(void){ erase(); }
  98.     int scalar(void) const { return count(); }
  99.  
  100.     operator void*() { return count()?this:0; } // so it can be used in tests
  101.     int isempty(void) const{ return !count(); } // for those that don't like the above (hi michael)
  102.  
  103.     T pop(void)
  104.     {
  105.     T tmp;
  106.     int n= count()-1;
  107.     if(n >= 0){
  108.         tmp= (*this)[n];
  109.         compact(n);
  110.     }
  111.     return tmp;
  112.     }
  113.  
  114.     void push(const T& a){ add(a);}
  115.     void push(const PerlList<T>& l);
  116.  
  117.     T shift(void)
  118.     {
  119.     T tmp= (*this)[0];
  120.     compact(0);
  121.     return tmp;
  122.     }
  123.     
  124.     int unshift(const T& a)
  125.     {
  126.     add(0, a);
  127.     return count();
  128.     }
  129.     
  130.     int unshift(const PerlList<T>& l);
  131.  
  132.     PerlList<T> reverse(void);
  133.     PerlList<T> sort();
  134.     
  135.     PerlList<T> splice(int offset, int len, const PerlList<T>& l);
  136.     PerlList<T> splice(int offset, int len);
  137.     PerlList<T> splice(int offset);
  138. };
  139.  
  140. // just a mechanism for self deleteing strings which can be hacked
  141. class TempString
  142. {
  143. private:
  144.     char *str;
  145. public:
  146.     TempString(const char *s)    
  147.     {
  148.         str= new char[strlen(s) + 1];
  149.         strcpy(str, s);
  150.     }
  151.     
  152.     TempString(const char *s, int len)    
  153.     {
  154.         str= new char[len + 1];
  155.         if(len) strncpy(str, s, len);
  156.         str[len]= '\0';
  157.     }
  158.  
  159.     ~TempString(){ delete [] str; }
  160.  
  161.     operator char*() const { return str; }
  162. };
  163.  
  164. /*
  165.  * This class takes care of the mechanism behind variable length strings
  166.  */
  167.  
  168. class VarString
  169. {
  170. private:
  171.     enum{ALLOCINC=32};
  172.     char *a;
  173.     int len;
  174.     int allocated;
  175.     int allocinc;
  176.     INLINE void grow(int n= 0);
  177.  
  178. public:
  179. #ifdef    USLCOMPILER
  180.     // USL 3.0 bug with enums losing the value
  181.     INLINE VarString(int n= 32);
  182. #else
  183.     INLINE VarString(int n= ALLOCINC);
  184. #endif
  185.  
  186.     INLINE VarString(const VarString& n);
  187.     INLINE VarString(const char *);
  188.     INLINE VarString(const char* s, int n);
  189.     INLINE VarString(char);
  190.  
  191.     ~VarString(){
  192. #       ifdef    DEBUG
  193.     fprintf(stderr, "~VarString() a= %p, allocinc= %d\n", a, allocinc);
  194. #       endif
  195.     delete [] a;
  196.     }
  197.  
  198.     VarString& operator=(const VarString& n);
  199.     VarString& operator=(const char *);
  200.  
  201.     INLINE const char operator[](const int i) const;
  202.     INLINE char& operator[](const int i);
  203.  
  204.     operator const char *() const{ return a; }
  205.  
  206.     int length(void) const{ return len; }
  207.  
  208.     void add(char);
  209.     void add(const char *);
  210.     void add(int, const char *);
  211.     void remove(int, int= 1);
  212.  
  213.     void erase(void){ len= 0; }
  214. };
  215.  
  216. class PerlStringList;
  217. //
  218. // Implements the perl specific string functionality 
  219. //
  220. class PerlString
  221. {
  222. private:
  223.     VarString pstr;  // variable length string mechanism
  224.     
  225. public:
  226.     class substring;
  227.     
  228.     PerlString():pstr(){}
  229.     PerlString(const PerlString& n) : pstr(n.pstr){}     
  230.     PerlString(const char *s) : pstr(s){}
  231.     PerlString(const char c) : pstr(c){}
  232.     PerlString(const substring& sb) : pstr(sb.pt, sb.len){}
  233.     
  234.     PerlString& operator=(const char *s){pstr= s; return *this;}        
  235.     PerlString& operator=(const PerlString& n); 
  236.     PerlString& operator=(const substring& sb);
  237.  
  238.     operator const char*() const{return pstr;}
  239.     const char operator[](int n) const{ return pstr[n]; }
  240.  
  241.     int length(void) const{ return pstr.length(); }
  242.     
  243.     char chop(void);
  244.     
  245.     int index(const PerlString& s, int offset= 0);    
  246.     int rindex(const PerlString& s, int offset= -1);
  247.     substring substr(int offset, int len= -1);
  248.     substring substr(const Range& r){ return substr(r.start(), r.length());}
  249.         
  250.     int m(const char *, const char *opts=""); // the regexp match m/.../ equiv
  251.     int m(Regexp&);
  252.     int m(const char *, PerlStringList&, const char *opts="");
  253.     int m(Regexp&, PerlStringList&);
  254.    
  255.     int tr(const char *, const char *, const char *opts="");
  256.     int s(const char *, const char *, const char *opts="");
  257.  
  258.     PerlStringList split(const char *pat= "[ \t\n]+", int limit= -1);
  259.     
  260.     int operator<(const PerlString& s) const { return (strcmp(pstr, s) < 0); }
  261.     int operator>(const PerlString& s) const { return (strcmp(pstr, s) > 0); }
  262.     int operator<=(const PerlString& s) const { return (strcmp(pstr, s) <= 0); }
  263.     int operator>=(const PerlString& s) const { return (strcmp(pstr, s) >= 0); }
  264.     int operator==(const PerlString& s) const { return (strcmp(pstr, s) == 0); }
  265.     int operator!=(const PerlString& s) const { return (strcmp(pstr, s) != 0); }
  266.     PerlString operator+(const PerlString& s) const;
  267.     PerlString operator+(const char *s) const;
  268.     PerlString operator+(char c) const;
  269.     friend PerlString operator+(const char *s1, const PerlString& s2);
  270.  
  271.     PerlString& operator+=(const PerlString& s){pstr.add(s); return *this;}
  272.     PerlString& operator+=(const char *s){pstr.add(s); return *this;}
  273.     PerlString& operator+=(char c){pstr.add(c); return *this;}
  274.     friend substring;
  275.  
  276. private:
  277.     void insert(int pos, int len, const char *pt, int nlen);
  278.  
  279.     // This idea lifted from NIH class library -
  280.     // to handle substring LHS assignment
  281.     // Note if subclasses can't be used then take external and make
  282.     // the constructors private, and specify friend PerlString
  283.     class substring
  284.     {
  285.     public:
  286.         int pos, len;
  287.     PerlString& str;
  288.     char *pt;
  289.     public:
  290.         substring(PerlString& os, int p, int l) : str(os)
  291.     {
  292.         if(p > os.length()) p= os.length();
  293.         if((p+l) > os.length()) l= os.length() - p;
  294.         pos= p; len= l;
  295.         if(p == os.length()) pt= 0; // append to end of string
  296.         else pt= &os.pstr[p];
  297.     }
  298.  
  299.         void operator=(const PerlString& s)
  300.         {
  301.             if(&str == &s){ // potentially overlapping
  302.         VarString tmp(s);
  303.         str.insert(pos, len, tmp, strlen(tmp));
  304.         }else str.insert(pos, len, s, s.length());
  305.         }
  306.         
  307.         void operator=(const substring& s)
  308.         {
  309.         if(&str == &s.str){ // potentially overlapping
  310.         VarString tmp(s.pt, s.len);
  311.         str.insert(pos, len, tmp, strlen(tmp));
  312.         }else str.insert(pos, len, s.pt, s.len);
  313.         }
  314.  
  315.         void operator=(const char *s)
  316.         {
  317.             str.insert(pos, len, s, strlen(s));
  318.         }
  319.     };
  320. };
  321.  
  322. class PerlStringList: public PerlList<PerlString>
  323. {
  324. public:
  325.     PerlStringList(int sz= 6):PerlList<PerlString>(sz){}
  326.     // copy lists, need to duplicate all internal strings
  327.     PerlStringList(const PerlStringList& n);
  328.  
  329.     PerlStringList& operator=(const PerlList<PerlString>& n);
  330.  
  331.     int split(const char *str, const char *pat= "[ \t\n]+", int limit= -1);
  332.     PerlString join(const char *pat= " ");
  333.     int m(const char *rege, const char *targ, const char *opts=""); // makes list of sub exp matches
  334.     PerlStringList grep(const char *rege, const char *opts=""); // trys rege against elements in list
  335. };
  336.  
  337. // This doesn't belong in any class
  338. inline PerlStringList m(const char *pat, const char *str, const char *opts="")
  339. {
  340. PerlStringList l;
  341.     
  342.     l.m(pat, str, opts);
  343.     l.shift(); // remove the first element which would be $&
  344.     return l;
  345. }
  346.  
  347. // Streams operators
  348. template <class T>
  349. istream& operator>>(istream& ifs, PerlList<T>& arr)
  350. {
  351. T a;
  352.     // Should I reset arr first?
  353.     arr.reset(); // I think so, to be consistent
  354.     
  355.     while(ifs >> a){
  356.     arr.push(a);
  357. //    cout << "<" << a << ">" << endl;
  358.     };
  359.     return ifs;    
  360. }
  361.  
  362. template <class T>
  363. ostream& operator<<(ostream& os,  const PerlList<T>& arr)
  364. {
  365.  
  366.     for(int i=0;i<arr.count();i++){
  367. #ifdef    TEST
  368.     os << "[" << i << "]" << arr[i] << " ";
  369.     }
  370.     os << endl; 
  371. #else
  372.     os << arr[i] << endl;
  373.     }
  374. #endif
  375.     return os;   
  376. }
  377.  
  378. istream& operator>>(istream& ifs, PerlString& s);
  379. istream& operator>>(istream& ifs, PerlStringList& sl);
  380. ostream& operator<<(ostream& os,  const PerlString& arr);
  381. ostream& operator<<(ostream& os,  const PerlStringList& arr);
  382.  
  383. // Implementation of template functions for perllistbase
  384. template <class T>
  385. INLINE T& PerlListBase<T>::operator[](const int i)
  386. {
  387.     assert((i >= 0) && (first >= 0) && ((first+cnt) <= allocated));
  388.     int indx= first+i;
  389.         
  390.     if(indx >= allocated){  // need to grow it
  391.     grow((indx-allocated)+allocinc, i+1); // index as yet unused element
  392.     indx= first+i;              // first will have changed in grow()
  393.     }
  394.     assert(indx >= 0 && indx < allocated);
  395.  
  396.     if(i >= cnt) cnt= i+1;  // it grew
  397.     return a[indx];
  398. }
  399.  
  400. template <class T>
  401. INLINE const T& PerlListBase<T>::operator[](const int i) const
  402. {
  403.      assert((i >= 0) && (i < cnt));
  404.      return a[first+i];
  405. }
  406.  
  407. template <class T>
  408. PerlListBase<T>::PerlListBase(const PerlListBase<T>& n)
  409. {
  410.     allocated= n.allocated;
  411.     allocinc= n.allocinc;
  412.     cnt= n.cnt;
  413.     first= n.first;
  414.     a= new T[allocated];
  415.     for(int i=0;i<cnt;i++) a[first+i]= n.a[first+i];
  416. #ifdef    DEBUG
  417.     fprintf(stderr, "PerlListBase(PerlListBase&) a= %p, source= %p\n", a, n.a);
  418. #endif
  419.  
  420. }
  421.  
  422. template <class T>
  423. PerlListBase<T>& PerlListBase<T>::operator=(const PerlListBase<T>& n){
  424. //  cout << "PerlListBase<T>::operator=()" << endl;
  425.     if(this == &n) return *this;
  426. #ifdef    DEBUG
  427.     fprintf(stderr, "~operator=(PerlListBase&) a= %p\n", a);
  428. #endif
  429.     delete [] a; // get rid of old one
  430.     allocated= n.allocated;
  431.     allocinc= n.allocinc;
  432.     cnt= n.cnt;
  433.     first= n.first;
  434.     a= new T[allocated];
  435.     for(int i=0;i<cnt;i++) a[first+i]= n.a[first+i];
  436. #ifdef    DEBUG
  437.     fprintf(stderr, "operator=(PerlListBase&) a= %p, source= %p\n", a, n.a);
  438. #endif
  439.     return *this;
  440. }
  441.  
  442. template <class T>
  443. void PerlListBase<T>::grow(int amnt, int newcnt){
  444.     if(amnt <= 0) amnt= allocinc; // default value
  445.     if(newcnt < 0) newcnt= cnt;   // default
  446.     allocated += amnt;
  447.     T *tmp= new T[allocated];
  448.     int newfirst= (allocated>>1) - (newcnt>>1);
  449.     for(int i=0;i<cnt;i++) tmp[newfirst+i]= a[first+i];
  450. #ifdef    DEBUG
  451.     fprintf(stderr, "PerlListBase::grow() a= %p, old= %p, allocinc= %d\n", tmp, a, allocinc);
  452.     fprintf(stderr, "~PerlListBase::grow() a= %p\n", a);
  453. #endif
  454.     delete [] a;
  455.     a= tmp;
  456.     first= newfirst;
  457. }
  458.  
  459. template <class T>
  460. void PerlListBase<T>::add(const T& n){
  461.     if(cnt+first >= allocated) grow();
  462.     a[first+cnt]= n;
  463.     cnt++;
  464. }
  465.  
  466. template <class T>
  467. void PerlListBase<T>::add(const int ip, const T& n){
  468.     assert(ip >= 0);
  469.     if(first == 0 || (first+cnt) >= allocated) grow();
  470.     assert((first > 0) && ((first+cnt) < allocated));
  471.     if(ip == 0){ // just stick it on the bottom
  472.         first--;
  473.         a[first]= n;
  474.     }else{
  475.         for(int i=cnt;i>ip;i--) // shuffle up
  476.         a[first+i]= a[(first+i)-1];
  477.         a[first+ip]= n;
  478.     }
  479.     cnt++;
  480. }
  481.  
  482. template <class T>
  483. void PerlListBase<T>::compact(const int n){ // shuffle down starting at n
  484. int i;
  485.     assert((n >= 0) && (n < cnt));
  486.     if(n == 0) first++;
  487.     else for(i=n;i<cnt-1;i++){
  488.         a[first+i]= a[(first+i)+1];
  489.     }
  490.     cnt--;
  491. }
  492.  
  493.  
  494. // implementation of template functions for perllist
  495.  
  496. template <class T>
  497. void PerlList<T>::push(const PerlList<T>& l)
  498. {
  499.     for(int i=0;i<l.count();i++)
  500.     add(l[i]);
  501. }
  502.  
  503. template <class T>
  504. int PerlList<T>::unshift(const PerlList<T>& l)
  505. {
  506.     for(int i=l.count()-1;i>=0;i--)
  507.     unshift(l[i]);
  508.     return count();
  509. }
  510.  
  511. template <class T>
  512. PerlList<T> PerlList<T>::reverse(void)
  513. {
  514.     PerlList<T> tmp;
  515.     for(int i=count()-1;i>=0;i--)
  516.     tmp.add((*this)[i]);
  517.     
  518.     return tmp;    
  519. }
  520.  
  521. template <class T>
  522. PerlList<T> PerlList<T>::sort(void)
  523. {
  524. PerlList<T> tmp(*this);
  525. int n= tmp.scalar();
  526.  
  527.     for(int i=0;i<n-1;i++)
  528.     for(int j=n-1;i<j;j--)
  529.         if(tmp[j] < tmp[j-1]){
  530.         T temp = tmp[j];
  531.         tmp[j] = tmp[j-1];
  532.         tmp[j-1]= temp;
  533.         }
  534.     
  535.     return tmp;    
  536. }
  537.  
  538. template <class T>
  539. PerlList<T> PerlList<T>::splice(int offset, int len, const PerlList<T>& l)
  540. {
  541. PerlList<T> r= splice(offset, len);
  542.  
  543.     if(offset > count()) offset= count();
  544.     for(int i=0;i<l.count();i++){
  545.     add(offset+i, l[i]);    // insert into list
  546.     }
  547.     return r;
  548. }
  549.  
  550. template <class T>
  551. PerlList<T>  PerlList<T>::splice(int offset, int len)
  552. {
  553. PerlList<T> r;
  554.  
  555.     if(offset >= count()) return r;
  556.     for(int i=offset;i<offset+len;i++){
  557.         r.add((*this)[i]);
  558.     }
  559.  
  560.     for(i=offset;i<offset+len;i++)
  561.     compact(offset);
  562.     return r;
  563. }
  564.  
  565. template <class T>
  566. PerlList<T>  PerlList<T>::splice(int offset)
  567. {
  568. PerlList<T> r;
  569.  
  570.     if(offset >= count()) return r;
  571.     for(int i=offset;i<count();i++){
  572.     r.add((*this)[i]);
  573.     }
  574.  
  575.     int n= count(); // count() will change so remember what it is
  576.     for(i=offset;i<n;i++)
  577.     compact(offset);
  578.     return r;
  579. }
  580.  
  581. // VarString Implementation
  582. INLINE VarString::VarString(int n)
  583. {
  584.     a= new char[n];
  585.     *a= '\0';
  586.     len= 0;
  587.     allocated= n;
  588.     allocinc= n;
  589. #   ifdef    DEBUG
  590.     fprintf(stderr, "VarString(int %d) a= %p\n", allocinc, a);
  591. #   endif
  592. }
  593.  
  594. INLINE VarString::VarString(const char* s)
  595. {
  596.     int n= strlen(s) + 1;
  597.     a= new char[n];
  598.     strcpy(a, s);
  599.     len= n-1;
  600.     allocated= n;
  601.     allocinc= ALLOCINC;
  602. #   ifdef    DEBUG
  603.     fprintf(stderr, "VarString(const char *(%d)) a= %p\n", allocinc, a);
  604. #   endif
  605. }
  606.  
  607. INLINE VarString::VarString(const char* s, int n)
  608. {
  609.     a= new char[n+1];
  610.     if(n) strncpy(a, s, n);
  611.     a[n]= '\0';
  612.     len= n;
  613.     allocated= n+1;
  614.     allocinc= ALLOCINC;
  615. #   ifdef    DEBUG
  616.     fprintf(stderr, "VarString(const char *, int(%d)) a= %p\n", allocinc, a);
  617. #   endif
  618. }
  619.  
  620. INLINE VarString::VarString(char c)
  621. {
  622.     int n= 2;
  623.     a= new char[n];
  624.     a[0]= c; a[1]= '\0';
  625.     len= 1;
  626.     allocated= n;
  627.     allocinc= ALLOCINC;
  628. #   ifdef    DEBUG
  629.     fprintf(stderr, "VarString(char (%d)) a= %p\n", allocinc, a);
  630. #   endif
  631. }
  632.  
  633.  
  634. INLINE ostream& operator<<(ostream& os,  const VarString& arr)
  635. {
  636. #ifdef TEST
  637.     os << "(" << arr.length() << ")" << (const char *)arr;
  638. #else
  639.     os << (const char *)arr;
  640. #endif
  641.     
  642.     return os;    
  643. }
  644.  
  645. INLINE const char VarString::operator[](const int i) const
  646. {
  647.      assert((i >= 0) && (i < len) && (a[len] == '\0'));
  648.      return a[i];
  649. }
  650.  
  651. INLINE char& VarString::operator[](const int i)
  652. {
  653.      assert((i >= 0) && (i < len) && (a[len] == '\0'));
  654.      return a[i];
  655. }
  656.  
  657. INLINE VarString::VarString(const VarString& n)
  658. {
  659.     allocated= n.allocated;
  660.     allocinc= n.allocinc;
  661.     len= n.len;
  662.     a= new char[allocated];
  663.     strcpy(a, n.a);
  664. #ifdef    DEBUG
  665.     fprintf(stderr, "VarString(VarString&) a= %p, source= %p\n", a, n.a);
  666. #endif
  667.  
  668. }
  669. #endif
  670.  
  671.